using System.Text.Json;
using Launcher;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Physical;
using SimpleServer;

var config = JsonSerializer.Deserialize<AppConfig>(File.ReadAllText("config.json"));
if (config == null)
{
    throw new Exception("config.json not found");
}

var refreshLock = new object();

if (!Directory.Exists(config.DataRootPath))
{
    Directory.CreateDirectory(config.DataRootPath);
}
var dataPath = Path.IsPathRooted(config.DataRootPath) ? config.DataRootPath : Path.Combine(Directory.GetCurrentDirectory(), config.DataRootPath);
dataPath = dataPath.Replace("\\", "/");
if (!dataPath.EndsWith('/'))
{
    dataPath += '/';
}
var channelInfo = new ChannelInfo();
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
if (!int.TryParse(config.ServerPort, out var port))
{
    port = 6666;
}
builder.WebHost.UseKestrel(options => options.ListenAnyIP(port));
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseRouting();
app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    RequestPath = "/data",
    FileProvider = new PhysicalFileProvider(dataPath,ExclusionFilters.None),
    ServeUnknownFileTypes = true,
    DefaultContentType = "application/octet-stream",
    OnPrepareResponse = ctx =>
    {
        if (ctx.Context.Request.Path.StartsWithSegments("/data") &&
            ctx.Context.Request.Path.Value?.EndsWith(".json") == false)
        {
            var path = ctx.File.Name;
            ctx.Context.Response.Headers["Content-Disposition"]= $"attachment; filename=\"{Path.GetFileName(path)}\"";
        }
    },
    
});

app.MapGet("/info", GetInfo);
app.MapGet("/refresh", GetRefresh);

Refresh();
app.Run();
return;

async Task GetInfo(HttpContext context)
{
    string result;
    lock (refreshLock)
    {
        var platform = context.Request.Query.ContainsKey("platform") ? context.Request.Query["platform"].ToString() : "windows";
        var info = new ChannelInfo();
        foreach (var channel in channelInfo.Channels)
        {
            if (channel.Platform.Equals(platform, StringComparison.OrdinalIgnoreCase))
            {
                info.Channels.Add(channel);
            }
        }
        result = JsonSerializer.Serialize(info);
    }
    context.Response.StatusCode = StatusCodes.Status200OK;
    await context.Response.WriteAsync(result);
}

async Task GetRefresh(HttpContext context)
{
    lock (refreshLock)
    {
       Refresh();
    }
    Console.WriteLine("refresh");
    context.Response.StatusCode = StatusCodes.Status200OK;
    await context.Response.WriteAsync("successfully");
}

void Refresh()
{
    channelInfo.Channels.Clear();
    var directoryInfo = new DirectoryInfo(dataPath);
    var channelsJson = directoryInfo.GetFiles("channel.json", SearchOption.AllDirectories);
    foreach (var channelJson in channelsJson)
    {
        Channel? channel;
        try
        {
            channel = JsonSerializer.Deserialize<Channel>(File.ReadAllText(channelJson.FullName));
        }
        catch (Exception e)
        {
            Console.Error.WriteLine($"{channelJson.FullName} 解析失败");
            Console.WriteLine(e);
            continue;
        }

        if (channel == null)
        {
            Console.Error.WriteLine($"{channelJson.FullName} 解析失败");
            continue;
        }
        
        channelInfo.Channels.Add(channel);
        RefreshChannel(channel,channelJson.Directory);
    }
}

void RefreshChannel(Channel channel,DirectoryInfo? directoryInfo)
{
    if (directoryInfo == null)
    {
        return;
    }

    var directories = directoryInfo.GetDirectories();
    if (directories.Length > config.KeepVersionCountPerPackage)
    {
        // 按时间倒叙
        var sortedDirectories = directories.OrderByDescending(fsi => fsi.LastWriteTime).ToList();
        for (int i = config.KeepVersionCountPerPackage; i < sortedDirectories.Count; i++)
        {
            try
            {
                sortedDirectories[i].Delete(true);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine($"删除文件夹失败:{sortedDirectories[i].FullName}");
                Console.Error.WriteLine(e);
            }
        }
        sortedDirectories.RemoveRange(config.KeepVersionCountPerPackage,sortedDirectories.Count - config.KeepVersionCountPerPackage);
        directories = sortedDirectories.ToArray();
    }
    foreach (var info in directories)
    {
        var resoucesJson = info.GetFiles("resources.json", SearchOption.TopDirectoryOnly);
        if (resoucesJson.Length == 0)
        {
            RefreshPackage(info);
            
            resoucesJson = info.GetFiles("resources.json", SearchOption.TopDirectoryOnly);
            if (resoucesJson.Length == 0)
            {
                continue;
            }
        }
        
        try
        {
            var resource = JsonSerializer.Deserialize<ResourceInfo>(File.ReadAllText(resoucesJson[0].FullName));
            if (resource == null)
            {
                Console.Error.WriteLine($"{resoucesJson[0].FullName} 解析失败");
                continue;
            }

            var rootPath = info.FullName.Replace('\\','/').Replace(dataPath, "");
            var infoPath = resoucesJson[0].FullName.Replace('\\','/').Replace(dataPath, "");
            channel.Packages.Add(new Package
            {
                Version = resource.Version, 
                ResourceInfoUrl = $"http://{config.ServerUrl}:{config.ServerPort}/data/{infoPath}" ,
                ResourceRootUrl = $"http://{config.ServerUrl}:{config.ServerPort}/data/{rootPath}/",
            });
        }
        catch (Exception e)
        {
            Console.Error.WriteLine($"{resoucesJson[0].FullName} 解析失败");
            Console.Error.WriteLine(e);
        }
    }
}

void RefreshPackage(DirectoryInfo? directoryInfo)
{
    if (directoryInfo == null)
    {
        return;
    }
    
    try
    {
        var resourceInfo = new ResourceInfo
        {
            Version = directoryInfo.LastWriteTime.ToString("yyyyMMddHHmmss")
        };
        var allFiles = directoryInfo.GetFiles("*",SearchOption.AllDirectories);
        var directoryPath = directoryInfo.FullName.Replace('\\', '/') + '/';
        foreach (var file in allFiles)
        {
            resourceInfo.Resources.Add(new Resource
            {
                Hash = file.Length.GetHashCode().ToString(),
                Path = file.FullName.Replace('\\','/').Replace(directoryPath,""),
                Size = file.Length
            });
        }
        File.WriteAllText(Path.Combine(directoryInfo.FullName,"resources.json"),JsonSerializer.Serialize(resourceInfo));
    }
    catch (Exception e)
    {
        Console.Error.WriteLine($"收集目录内资源发生异常:{directoryInfo.FullName}");
        Console.Error.WriteLine(e);
    }
}